﻿using EnetaMvc.ApplicationServices;
using EnetaMvc.ApplicationServices.Dto;
using EnetaMvc.Web.Attributes;
using EnetaMvc.Web.Extensions;
using EnetaMvc.Web.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace EnetaMvc.Web.Controllers
{
    [HandleError]
    public class ForumsController : Controller
    {
        private readonly IForumService _forumService;
        private readonly IUserService _userService;

        public ForumsController(IForumService forumService, IUserService userService)
        {
            _forumService = forumService;
            _userService = userService;
        }

        protected override void OnException(ExceptionContext filterContext)
        {
            //base.OnException(filterContext);

            Response.ContentType = "text/plain";
            Response.Write(filterContext.Exception);
            Response.End();
        }

        public ActionResult Index()
        {
            var categories = _forumService.ListForumCategories();

            return View(categories);
        }

        public ActionResult Category(long id)
        {
            var category = _forumService.GetForumCategoryById(id);

            return View(category);
        }

        public ActionResult Forum(long id, int page = 1)
        {
            var model = new ForumViewModel();
            model.Forum = _forumService.GetForumById(id);
            model.Posts = _forumService.ListPostsForForum(id, page, 20);

            return View(model);
        }

        public ActionResult Topic(long id)
        {
            var model = new ForumTopicModel();
            model.Posts = _forumService.GetForumThread(id);
            model.Forum = _forumService.GetForumByPostId(id);

            _forumService.IncreaseTopicViewCount(id);

            return View(model); 
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "User, Administrator")]
        public ActionResult Reply(long id)
        {
            var model = new ForumReplyModel();
            model.Post = _forumService.GetPostById(id);

            return View(model);
        }

        [HttpPost]
        [ValidateInput(false)]
        [EnetaAuthorize(Roles = "User, Administrator")]
        public ActionResult Reply(ForumReplyModel model, long id)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            if (string.IsNullOrWhiteSpace(Util.StripTags(model.Reply)))
            {
                ModelState.AddModelError("Reply", "EMPTY!");
                model.Post = _forumService.GetPostById(id);
                return View(model);
            }

            _forumService.AddReplyToPost(id, User.Identity.Name, Util.StripForbiddenTags(model.Reply));

            var post = _forumService.GetPostById(id);

            return RedirectToAction("Topic", new { id = post.TopLevelPostId });
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "User, Administrator")]
        public ActionResult NewTopic(long id)
        {
            var forum = _forumService.GetForumById(id);
            if (forum == null)
                return HttpNotFound("Cannot find forum with id " + id);

            var model = new ForumTopicEditModel();
            model.Forum = forum;

            return View(model);
        }

        [HttpPost]
        [ValidateInput(false)]
        [EnetaAuthorize(Roles = "User, Administrator")]
        public ActionResult NewTopic(ForumTopicEditModel model, long id)
        {
            if (!ModelState.IsValid)
            {
                model.Forum = _forumService.GetForumById(id);
                return View(model);
            }

            if(string.IsNullOrWhiteSpace(Util.StripTags(model.Body)))
            {
                ModelState.AddModelError("Body", "EMPTY!");
                model.Forum = _forumService.GetForumById(id);
                return View(model);
            }

            _forumService.AddTopicToForum(id, User.Identity.Name, model.Title, Util.StripForbiddenTags(model.Body));
            return RedirectToAction("Forum", new { id = id });
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "User, Administrator")]
        public ActionResult Quote(long id)
        {
            var model = new ForumReplyModel();
            model.Post = _forumService.GetPostById(id);
            model.Reply = "[quote name=\""+ model.Post.CreatedByUserName +"\"]" + model.Post.Body + "[/quote]";

            return View("Reply", model);
        }

        [HttpPost]
        [ValidateInput(false)]
        [EnetaAuthorize(Roles = "User, Administrator")]
        public ActionResult Quote(ForumReplyModel model, long id)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            if (string.IsNullOrWhiteSpace(Util.StripTags(model.Reply)))
            {
                ModelState.AddModelError("Reply", "EMPTY!");
                model.Post = _forumService.GetPostById(id);
                return View("Reply",model);
            }

            _forumService.AddReplyToPost(id, User.Identity.Name, Util.StripForbiddenTags(model.Reply));

            var post = _forumService.GetPostById(id);

            return RedirectToAction("Topic", new { id = post.TopLevelPostId });
        }

        public ActionResult Rss()
        {
            var topics = _forumService.ListLastTopicsForRss();
            var urlPrefix = Url.Action("Topic",null, null, Request.Url.Scheme) + "/";
            var commentsUrlPrefix = Url.Action("TopicCommentsRss", null, null, Request.Url.Scheme) + "/";

            return new ContentRssResult(topics, Resources.EnetaMvc.RssAllForums, "", urlPrefix, commentsUrlPrefix, false);
        }

        public ActionResult RepliesRss()
        {
            var posts = _forumService.ListLastRepliesForRss();

            var urlPrefix = Url.Action("Topic", null, null, Request.Url.Scheme) + "/";

            return new ContentRssResult(posts, Resources.EnetaMvc.RssAllReplies, "", urlPrefix, null, true);
        }

        public ActionResult TopicCommentsRss(long id)
        {
            var posts = _forumService.GetForumThread(id);
            var topLevelPost = posts.Where(p => p.Id == id).FirstOrDefault();
            if (topLevelPost != null)
                posts.Remove(topLevelPost);

            var urlPrefix = Url.Action("Topic",null,null,Request.Url.Scheme) + "/" + id + "#";
            
            return new ContentRssResult(posts, Resources.EnetaMvc.RssAllReplies, "", urlPrefix, null, true);
        }

        public ActionResult CategoryRss(long id)
        {
            var category = _forumService.GetForumCategoryById(id);
            var posts = _forumService.ListLastTopicsForCategoryRss(id);

            var urlPrefix = Url.Action("Topic", null, null, Request.Url.Scheme) + "/";
            var commentsUrlPrefix = Url.Action("TopicCommentsRss", null, null, Request.Url.Scheme) + "/";

            return new ContentRssResult(posts, "RSS: " + category.Name, "", urlPrefix, commentsUrlPrefix, false);
        }

        public ActionResult ForumRss(long id)
        {
            var forum = _forumService.GetForumById(id);
            var posts = _forumService.ListPostsForForum(id, 1, 10).Results;

            var urlPrefix = Url.Action("Topic", null, null, Request.Url.Scheme) + "/";
            var commentsUrlPrefix = Url.Action("TopicCommentsRss", null, null, Request.Url.Scheme) + "/";

            return new ContentRssResult(posts, "RSS: " + forum.Name, "", urlPrefix, commentsUrlPrefix, false);
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult CreateCategory()
        {
            return View("EditCategory", new ForumCategoryDto());
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult CreateCategory(ForumCategoryDto category)
        {
            return EditCategory(category);
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult EditCategory(long id)
        {
            var category = _forumService.GetForumCategoryById(id);
            if (category == null)
                return HttpNotFound("Cannot find category with id " + id);

            return View(category);
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult EditCategory(ForumCategoryDto category)
        {
            if (!ModelState.IsValid)
            {
                return View("EditCategory",category);
            }

            _forumService.SaveCategory(category);

            return RedirectToAction("Index");
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult DeleteCategory(long id)
        {
            var category = _forumService.GetForumCategoryById(id);
            if (category == null)
                return HttpNotFound("Cannot find category " + id);

            return View(category);
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult DeleteCategoryConfirmed(long id)
        {
            _forumService.DeleteCategory(id);

            return RedirectToAction("Index");
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult CreateForum()
        {
            var model = new ForumEditModel();
            model.Forum = new ForumDto();

            FillForumEditModel(model);

            return View("EditForum", model);
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult CreateForum(ForumEditModel model, string[] moderatorList)
        {
            return SaveForum(model, moderatorList);
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult EditForum(long id)
        {
            var forum = _forumService.GetForumById(id);
            if (forum == null)
                return HttpNotFound("Cannot find forum " + id);

            var model = new ForumEditModel();
            model.Forum = forum;

            FillForumEditModel(model);

            return View(model);
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult EditForum(ForumEditModel model, string[] moderatorList)
        {
            return SaveForum(model, moderatorList);
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult DeleteForum(long id)
        {
            var forum = _forumService.GetForumById(id);
            if (forum == null)
                return HttpNotFound("Cannot find forum " + id);

            return View(forum);
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult DeleteForumConfirmed(long id)
        {
            _forumService.DeleteForum(id);

            return RedirectToAction("Index");
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult DeletePost(long id)
        {
            var post = _forumService.GetPostById(id);
            if (post == null)
                return HttpNotFound("Cannot find post " + id);

            return View(post);
        }

        [HttpPost]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult DeletePostConfirmed(long id)
        {
            _forumService.DeletePost(id);

            return RedirectToAction("Index");
        }

        [HttpGet]
        [EnetaAuthorize(Roles = "Administrator")]
        public ActionResult GetUserNamesAutoComplete(string id)
        {
            var users = _userService.FindUsers(id);
            var result = users.Select(u => u.UserName).ToArray();

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        [NonAction]
        private ActionResult SaveForum(ForumEditModel model, string[] moderatorList)
        {
            if (!ModelState.IsValid)
            {
                FillForumEditModel(model);
                return View("EditForum", model);
            }

            var forum = model.Forum;
            forum.Moderators = new UserDto[] {};

            if (moderatorList != null)
            {
                var moderList = new List<UserDto>();

                foreach(var moder in moderatorList)
                {
                    var user = _userService.GetUserByUserName(moder);
                    if (user == null)
                        continue;
                    if (moderList.Contains(user))
                        continue;

                    moderList.Add(user);
                }

                forum.Moderators = moderList.ToArray();
            }

            _forumService.SaveForum(forum);

            return RedirectToAction("Index");
        }

        [NonAction]
        private void FillForumEditModel(ForumEditModel model)
        {
            long selected = 0;
            if(model.Forum != null)
                selected = model.Forum.Id;
            
            model.Categories = _forumService.ListForumCategories().ToSelectList(selected);

            if(model.Forum != null)
                model.Moderators = model.Forum.Moderators;

            if (model.Moderators == null)
                model.Moderators = new List<UserDto>();
        }
    }
}
